using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Net;
using System.Collections;
using System.Threading;
using System.Runtime.CompilerServices;
using System.Windows.Forms;

namespace CSharpXDL
{
    internal class DownLoad
    {
        String url;
        String fName;
        internal String[] args;
        Stream channel;
      //  Hashtable<char, long> bprMap = new Hashtable<char, long>();
        internal Dictionary<char, long> bprMap = new Dictionary<char, long>();
        Rate rate;
        internal bool completed=false;
        FileStream bprser;
        List<BlockDownloader> bdls;
        List<Thread> dlThreads;
        internal String bprFile;
        private int thread_total;

        public FileStream Bprser
        {
            get { return bprser; }
            set { bprser = value; }
        }

        public Stream Channel
        {
            get { return channel; }
            set { channel = value; }
        }

        public List<BlockDownloader> Bdls
        {
            get { return bdls; }
            set { bdls = value; }
        }

        public DownLoad(String[] args)
        {
		    this.args=args;
	    }
        [MethodImpl(MethodImplOptions.Synchronized)]
        public void Write(long position, byte[] buffer)
        {
          
                byte[] buffer2=buffer;
                channel.Seek(position, SeekOrigin.Begin);
                channel.Write(buffer2, 0, buffer2.Length);
                channel.Flush();
          
        }

        internal void complete(char fName)
        {
		lock (this) {
			--thread_total;

            System.Console.WriteLine(fName + " " + DateTime.Now.ToLocalTime()
					+ ""+" download completed! There are "+thread_total+" downloading");
			if (thread_total == 0){
				try {
                    completed = true;
					channel.Close();
				} catch (IOException e) {
                    Console.WriteLine(e.StackTrace);
				}
				System.Console.WriteLine(args[1]+" is download completed");
				//System.exit(0);
				
			}
				//merge();
		}
	}

        //http://xbox-ecn102.vo.msecnd.net/content/434307fc/SF4ArcadeEdition_Manual_Fix.pdf
      public  List<BlockDownloader> download()  {
		
		bdls = new List<BlockDownloader>();
		thread_total = 1;

		String[] urls=args[0].Split('`');

		int urlsL = urls.Length;
        long length = DataLength(urls[0]);
		if (args.Length > 2)
			thread_total = int.Parse(args[2]);
		long mod = length % thread_total;
		long partial = length / thread_total;
	//	bpr= File.Open(args[1]+".bpr",FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
        BinaryReader binReader=null;
          try {
            bprFile = args[1] + ".bpr";
			bprser=File.Open(args[1]+".bpr",FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
            binReader = new BinaryReader(bprser);
			//bprser.
			while(true)
                bprMap.Add(binReader.ReadChar(), binReader.ReadInt64());
            bprser.Close();
		} catch (Exception e) {
            if (binReader != null)
            {
                //binReader.Dispose();
                bprser.Close();
            }
          
            Console.WriteLine(e.StackTrace);
		}
        bprser = File.Open(args[1] + ".bpr", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
        channel = File.Open(args[1], FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
        //  channe
        channel.SetLength(length);
		
		
		BlockDownloader downloader = new BlockDownloader(this,urls[0], 'A', 0, partial);
        bdls.Add(downloader);
       
        dlThreads=new List<Thread>(thread_total);
        dlThreads.Add(new Thread(new ThreadStart(downloader.run)));

		for (int i = 1; i < thread_total; i++) {
			long p = partial * (i);
			if (i == thread_total - 1) {
				downloader = new BlockDownloader(this,urls[i%urlsL], (char)('A'+i),
						p, partial + mod);
			} else {
				
				downloader = new BlockDownloader(this,urls[i%urlsL], (char)('A'+i),
						p, partial);
			}
            bdls.Add(downloader);
            dlThreads.Add(new Thread(new ThreadStart(downloader.run)));
			
		}
        rate = new Rate(this, bdls, length);
        dlThreads.Add(new Thread(new ThreadStart(rate.run)));
		start();
        return bdls;
	}


    public long DataLength(String url1) {
        XDLConnect c= ConnectHelper.GetXDLConnect(url1, 0);
        return c.ContentLength();

        //http://epix.xbox.com/shaXam/0201/d9/a3/d9a3e63e-05fe-4a56-aa8c-925c66190a73.PDF?v=1#streetfighter4-u
	}
    public long getBpr(char key)
    {
		lock (this) {
            try
            {
                long p = bprMap[key];
                return p;//==null ? 0:p.longValue();
            }catch(Exception e){
                return 0;

            }
		}
	}
    


     public  void start()
        {
            foreach(Thread t in dlThreads){
                t.Start();
            }

        }


     public void Abort()
     {
         foreach (Thread t in dlThreads)
         {
             t.Abort();
         }

     }
     public void Suspend()
     {
         foreach (Thread t in dlThreads)
         {
             t.Suspend();
         }

     }
     public void Resume()
     {
         foreach (Thread t in dlThreads)
         {
             t.Resume();
         }

     }
     DataGridViewRow row;
     public System.Windows.Forms.DataGridViewRow DataGridViewRow
     {
         get { return row; }
         set { row = value; }
     }

     internal XDLForm xDLForm;
     internal void download(XDLForm xDLForm)
     {
         this.xDLForm = xDLForm;
         download();
     }
    }
}
